#requires –version 2.0

function Invoke-PSExec {
	param
(
		[Parameter(Position=0,Mandatory=$true)][string]$ComputerName,
		[Parameter(Mandatory=$true)][string]$SubScripts,
		[Parameter(Mandatory=$true)][string]$Assets,
		[Parameter(Mandatory=$true)][string]$RemoteCommand,
#		[Parameter(Mandatory=$false)][string]$logfile,
		[Parameter(Mandatory=$false)][int]$Timeout = '300'
		
	)
	# VARIABLES
	[string]$Notes = ''
	[boolean]$Success = $false
	[datetime]$SubStartTime = Get-Date
	[string]$ComputerName = $ComputerName.ToUpper()
	
	$exitcode = $null
	[string]$exitcodedesc = 'Unknown'
	[string]$PsExec = "$Assets\PsExec.exe"
	
	. "$SubScripts\Func_Get-Runtime_1.0.3.ps1"
	
	# REMOVE EXISTING OUTPUT PSOBJECT	
	if ($global:InvokePSExec) {
		Remove-Variable InvokePSExec -Scope "Global"
	}
	
	#region Tasks
	
		# BUILD ARGUMENT LIST STRING
		[string]$ArgumentList = ' -accepteula -s -h -n ' + $Timeout + ' \\' + $ComputerName + ' ' + $RemoteCommand
		
		# RUN PSEXEC
		[int]$loopcount = '0'
		Do {
			$loopcount++
			Try {
				$psexecprocess = Start-Process -FilePath $PsExec -ArgumentList $ArgumentList -Wait -PassThru -WindowStyle Hidden -ErrorAction Stop
				[boolean]$InvokePSExecerror = $false
			}
			Catch {
				[boolean]$InvokePSExecerror = $true
				Sleep -Seconds 1
			}
		}
		Until (($InvokePSExecerror -eq $false) -or ($loopcount -gt 10))
		
		if ($InvokePSExecerror -eq $false) {
			# CAPTURE EXIT CODE
			[string]$exitcode = $psexecprocess.ExitCode
			
			# DETERMINE SUCCESS
			if ($exitcode -eq '0') {
				[boolean]$Success = $true
			}
		
			# EXITCODE CROSSREFERENCE HASH (Library)
			$xreftable = @{
				0 = 'Successful'
				5 = 'Access is Denied'
				87 = 'The parameter is incorrect'
				233 = 'No process is on the other end of the pipe'
				1359 = 'An internal error occurred'
			}
			if (($xreftable.ContainsKey($exitcode)) -eq $true) {
				[string]$exitcodedesc = $xreftable[$exitcode]
			}
			else
{
				[string]$exitcodedesc = 'Unknown'
			}
		} # PSEXEC ran without errors
		else
{
			[string]$exitcode = 'ERROR'
			[string]$exitcodedesc = "PSEXEC COULD NOT RUN AFTER $loopcount TRIES"
		}
		
	#endregion Tasks
	
	Get-Runtime -StartTime $SubStartTime
	
	# Create Results Custom PS Object
	$global:InvokePSExec = New-Object -TypeName PSObject -Property @{
		ComputerName = $ComputerName
		Success = $Success
		Notes = $Notes
		Starttime = $SubStartTime
		Endtime = $global:GetRunTime.Endtime
		Runtime = $global:GetRunTime.Runtime
		ExitCode = $exitcode
		PSExecProcess = $psexecprocess
		ExitCodeDesc = $exitcodedesc
		LoopCount = $loopcount
	}
}

#region Notes

<# Description
	Run commands on remote computer using PSExec.exe
#>

<# Author
	Levon Becker
	PowerShell.Guru@BonusBits.com
	http://wiki.bonusbits.com
#>

<# Dependents
	Func_Invoke-Patching
	Test-WSUSClient
#>

<# Dependencies
	Func_Get-Runtime
#>

<# Change Log
	1.0.0 - 02/08/2012
		Created
	1.0.1 - 02/08/2012
		Removed the SubFunction (Didn't give me -ErrorAction or -ErrorVariable option like I hoped)
		Removed Try/Catch (Three errors come out and it stops at the first before it finishes)
		Added TimeOut parameter
		Renamed $commands to $RemoteCommand
	1.0.2 - 02/09/2012
		Changing to Start-Process instead of dot sourcing
	1.0.3 - 02/09/2012
		Added ExitCode output
		Added -WindowStyle Hidden to Start-Process
		Changed to capture the who process output and included it in subscript output
	1.0.4 - 02/10/2012
		Added Hash Table for exitcode descriptions
		Added ExitCodeDesc to output
		Changed -i to -h
	1.0.5 - 02/10/2012
		Added Try/Catch
	1.0.6 - 04/20/2012
		Changed parameter names
#>

<# Sources
	Windows System Error Codes
		http://www.symantec.com/connect/articles/windows-ComputerName-error-codes-exit-codes-description
#>

#endregion Notes
